<?
/**
 * ЭТОТ КЛАСС БОЛЬШЕ НЕ ИСПОЛЬЗУЕТСЯ
 * @deprecated
 */
ini_set('display_errors',1);
error_reporting(E_ALL);

$dbus = new Dbus(Dbus::BUS_SESSION, true);

$n = $dbus->createProxy('com.Skype.API', '/com/Skype', 'com.Skype.API');
$n->Invoke('NAME REDMINE.BOT');
$n->Invoke('PROTOCOL 8');

$dbus->registerObject('/com/Skype/Client', 'com.Skype.API.Client', 'phpSkype'); //Регистрируем просмотр уведомлений скайпа

while(1) {
    $s = $dbus->waitLoop(1);
}

/*  ============================================   */

class phpSkype {

    public static function notify($notify) {

        if (preg_match('/RECEIVED/', $notify)) {
            $messageId = explode(' ', $notify);
            Bot::getInstance()->getDetails($messageId[1]);
        }
    }
}


/*  ============================================   */


class RedmineApi
{
    //типы действий
    const CREATE_ISSUE   = '!newtask'; // !newtask [Name]; [Description];[tracker]; | !новая
    const CHANGE_PROJECT = '!changep'; // !changep [id]                             | !смпроект
    const ON_TEST        = '!ontest' ; // !ontest  [id]                             | !натест            ----issue_status_id //писать в скайп тестировщику номер задачи fs.QA
    const ASSIGN_USER    = '!assign' ; // !assign  [playformid]                     | !назначить
    const GET_MY_TASKS   = '!mytasks'; // !mytasks                                  | !мои
    const GET_TASK       = '!task'   ; // !task    [id]                             | !таск
    const GET_PROJECTS   = '!listp'  ; // !listp                                    | !проекты
    const CLOSE_ISSUE    = '!close'  ; // !close                                    | !закрыть
    const HELP           = '!help'   ; // !help                                     | !помощь
    const COMMENT        = '!comment'; // !comment [id]
    const PROJECT        = '!curp'   ; // !project [id]
    const EXIT_PROJECT   = '!exitp'  ;
    const GET_CURRENT_PROJECT = '!getcurp';
    //типы тасков
    const TYPE_TESTING  = 5;
    const TYPE_DEFECTED = 4;
    const TYPE_DEVELOP  = 9;

    //приоритеты задачи
    const PRIORITY_NEED_THINK  = 10;
    const PRIORITY_DEVELOPMENT = 3;
    const PRIORITY_NORMAL      = 4;
    const PRIORITY_HIGHT       = 5;
    const PRIORITY_URGENT      = 6;

    //родительские проекты
    const PROJECT_TESTS          = 21;
    const PROJECT_PETS           = 31;
    const PROJECT_BILLING        = 65;
    const PROJECT_MEETING        = 44;
    const PROJECT_SUPPORT        = 72;
    const PROJECT_VOTE           = 32;
    const PROJECT_MOBILE_VERSION = 24;
    const PROJECT_SOCIAL         = 29;
    const PROJECT_FS_2_0         = 92;
    const PROJECT_OTHER          = 0;

    const DOMEN    = 'http://pm.vs58.net/';
    private $login = 'stats';
    private $path  = 'Pass@word1';
    private $currentProject;
    private $currentIssueId;

    public function getCurrentProject()
    {
        return ($this->currentProject) ? $this->currentProject : 0;
    }

    public function getCurrentIssueId()
    {
        return $this->currentIssueId;
    }

    public function setCurrentProject($value)
    {
        $this->currentProject = $value;
        return $this;
    }

    public function setCurrentIssue($value)
    {
        $this->currentIssueId = $value;
    }

    //мапа для команд на русском языке
    private $mapCommands = array(
        self::CREATE_ISSUE   => '!новая',
        self::CHANGE_PROJECT => '!измпроект',
        self::ON_TEST        => '!натест' ,
        self::ASSIGN_USER    => '!назначить',
        self::GET_MY_TASKS   => '!мои',
        self::GET_TASK       => '!таск',
        self::GET_PROJECTS   => '!проекты',
        self::CLOSE_ISSUE    => '!закрыть',
        self::HELP           => '!помощь',
        self::COMMENT        => '!коммент',
        self::PROJECT        => '!текпроект',
        self::EXIT_PROJECT   => '!выхпроект'  ,
        self::GET_CURRENT_PROJECT => '!идтекпроект',

    );

    private $mapDescriptions = array(
        self::CREATE_ISSUE   => 'Создать новую задачу в redmine. Пример: !newtask [название задачи]; [описание задачи]; ',
        self::CHANGE_PROJECT => 'Изменить проект у задачи. Пример:!changep [id таска]; [id проекта]; ',
        self::ON_TEST        => 'Отправить задачу на тестирование. Пример: !ontest [id задачи]' ,
        self::ASSIGN_USER    => 'Назначить человека на задачу.',
        self::GET_MY_TASKS   => 'Получить список из раздела "Мои задачи"',
        self::GET_TASK       => 'Получить таск по его id. Пример: !task [id задачи]',
        self::GET_PROJECTS   => 'Получить список всех проектов',
        self::CLOSE_ISSUE    => 'Закрыть задачу. Пример: !close [id задачи]',
        self::HELP           => 'Помощь. Пример: !help',
        self::COMMENT        => 'Создание комментария к задаче. Пример: !comment [id задачи]; [комментарий]',
        self::PROJECT        => 'Установить текущий проект. Пример: !curp [id проекта]',
        self::EXIT_PROJECT   => 'Выйти из текущего проекта. Пример: !exitp '  ,
        self::GET_CURRENT_PROJECT => 'Узнать в каком проекте ты сейчас находишься. Пример: !getcurp',
    );

    private static $linksProjects = array(
        self::PROJECT_PETS => array(30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 68),
        self::PROJECT_BILLING => array(),
        self::PROJECT_MEETING => array(23, 59, 60, 61, 89),
        self::PROJECT_SUPPORT => array(),
        self::PROJECT_VOTE => array(),
        self::PROJECT_MOBILE_VERSION => array(),
        self::PROJECT_SOCIAL => array(),
        self::PROJECT_FS_2_0 => array(),
        self::PROJECT_OTHER => array(),
    );

    public function curlRequest($url, $method = 'GET', $data = array())
    {
        $authorization = base64_encode($this->login . ':' . $this->path);
        var_dump($authorization);
        $data = json_encode(array(
            'issue' => $data,
        ));

        $options = array(
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => array(
                'Accept: application/json',
                'Content-Type: application/json',
                'Authorization: Basic ' . $authorization
            ),
        );

        switch ($method) {
            case 'GET':
                $options[CURLOPT_POSTFIELDS] = $data;
                break;

            case 'POST':
                $options[CURLOPT_POST]       = true;
                $options[CURLOPT_POSTFIELDS] = $data;
                break;

            case 'PUT':
                $options[CURLOPT_CUSTOMREQUEST] = 'PUT';
                $options[CURLOPT_POSTFIELDS]    = $data;
                break;

            case 'DELETE':
                $options[CURLOPT_CUSTOMREQUEST] = 'DELETE';
                break;
        }

        $curl = curl_init();
        curl_setopt_array($curl, $options);
        $resp = curl_exec($curl);
        curl_close($curl);
        $result = json_decode($resp, true);

        return $result;
    }

    public function getIssueById($id)
    {
        return self::DOMEN . 'issues/'. $id;
    }

    public function getParentProjectIdByProjectId($id)
    {
        foreach (self::$linksProjects as $parentProjectId => $subProjectsIds) {
            if ($parentProjectId == $id || in_array($id, $subProjectsIds)) {
                return $parentProjectId;
            }
        }

        return self::PROJECT_OTHER;
    }

    /**
     * @param string $name - имя таска
     * @param int    $idProject
     * @param string $description
     * @param int    $tracker
     * @return bool
     */
    public function createTask($name, $idProject, $description, $tracker)
    {

        if (!$name || !$idProject || !$description || !$tracker) {
            return false;
        }

        $data = array(
            'description' => $description,
            'tracker_id'  => intval($tracker),
            'project_id'  => intval($idProject),
            'subject'     => $name,
        );

        $res = $this->curlRequest(self::DOMEN . 'issues.json', 'POST', $data, true);
        return $res;
    }

    public function changeIssueStatus($issueId, $statusId)
    {
        if (!$issueId || !$statusId) {
            return false;
        }

        $url = 'issues/' . $issueId . '.json';
        $data = array('status_id' => $statusId);
        $this->curlRequest(self::DOMEN . $url, 'PUT', $data);
        return true;
    }

    public function closeIssue($issueId) {
        $issueId = intval($issueId);

        if (!$issueId) {
            return false;
        }

        $this->changeIssueStatus($issueId, 5);

        return true;
    }

    public function changeComment($issueId, $comment)
    {
        if (!$issueId || !$comment) {
            return false;
        }

        $url = 'issues/' . $issueId . '.json';
        $data = array('description' => $comment);
        $this->curlRequest(self::DOMEN . $url, 'PUT', $data);
        return true;
    }
    public function getHelp()
    {
        $help = '';
        foreach ($this->mapDescriptions as $command => $desc) {
            $russian = $this->mapCommands[$command];
            $help .= $command . '[' . $russian . ']' . ' - ' . $desc  . "\n";
        }
        return $help;
    }

    public function changeProject($issueId, $proejctId)
    {
        if (!$issueId || !$proejctId) {
            return false;
        }

        $url = 'issues/' . $issueId . '.json';
        $data = array('project_id' => $proejctId);
        $this->curlRequest(self::DOMEN . $url, 'PUT', $data);
        return true;
    }

    public function getMapCommands()
    {
        return $this->mapCommands;
    }
}

/*  ============================================   */

class Bot
{

    private static $lastId;
    private $redmineApi = null;

    private static $instance = null;

    public static function getInstance()
    {
        if (!self::$instance) {
            self::$instance = new Bot();
        }

        return self::$instance;

    }
    private function __construct()
    {
      $this->redmineApi = new RedmineApi();
    }

    public static function getDetails($messageId)
    {
        global $n;

        $ch   = $n->Invoke('GET CHATMESSAGE '.$messageId.' CHATNAME');
        $mess = $n->Invoke('GET CHATMESSAGE '.$messageId.' BODY');
        $auth = $n->Invoke('GET CHATMESSAGE '.$messageId.' FROM_DISPNAME');
        $login = $n->Invoke('GET CHATMESSAGE '.$messageId.' FROM_HANDLE');

        /* Автора сообщения, id чата и текст сообщения.*/
        $author  = explode('FROM_DISPNAME ', $auth);
        $chat    = explode('CHATNAME ', $ch);
        $message = explode('BODY ', $mess);
        echo $login;
        if (isset($author[1]) AND isset($message[1])) {
            echo $author[1].': '.$message[1]."\n"; //Выводим в консоль автора и сообщение
        }

        /* вызываем обработку сообщения только когда оно начинается на "!" */
        if ($message[1][0] == '!') {
            Bot::getInstance()->reply($chat[1], $message[1], $messageId);
        }
    }

    public function reply($chat, $message, $id)
    {
        global $n;
        //если id cообщения, на которое нужно ответить, меньше чем id предыдущего, то ответа не будет.
        self::$lastId = $message;

        if (self::$lastId <= $message) {

            $reply = $this->getReply($message);
            if ($reply != '' || !empty($reply)) $n->Invoke('CHATMESSAGE '.$chat.' '.$reply); //Посылаем сообщение
        } else {
            echo 'has been answer' . "\n";
        }
    }

    public function getMsgParams($message)
    {
        //$params = preg_split('/\"(.+?)\"/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
//        preg_match_all('/\"(?:\\.|[^\\\"])*\"|\\S+/', $message, $params);
        $paramsFromMsg  = array();
        $stringParams = '';
        list($command, $stringParams) = preg_split('# #', $message, 2);
        $params[0] = $command;

        if ($stringParams) {
            $paramsFromMsg = explode(';', $stringParams);
        }

        foreach ($paramsFromMsg as $paramFromMsg) {
            if (!empty($paramFromMsg)) {
                $paramFromMsg = trim($paramFromMsg);
            }
            $params[] = $paramFromMsg;
        }

        return $params;
    }

    /**
     * @param string $message
     *
     * @return string
     */
    public function actionCommand($message)
    {
        $redmineApi = $this->redmineApi;
        $commands = $redmineApi->getMapCommands();
        $msgParams = $this->getMsgParams($message);
        $action = '';

        foreach ($commands as $command => $commandRus) {
            if (trim($msgParams[0]) == $command || trim($msgParams[0]) == $commandRus) {
                $action = $command;
                break;
            }
        }

        if (empty($action)) {
            return ' Команда не найдена. Чтобы просмотреть все доступные команды, используйте !help';
        }

        switch ($action) {
            case RedmineApi::HELP:
                $reply = $redmineApi->getHelp();

                break;
            case RedmineApi::CREATE_ISSUE:
                $name        = isset($msgParams[1]) ? $msgParams[1] : 'new task from skype';
                $description = isset($msgParams[2]) ? $msgParams[2] : 'comment';
                $projectId   = $redmineApi->getCurrentProject();

                if ($projectId) {
                    $trackerId   = RedmineApi::TYPE_DEVELOP;
                    $res = $redmineApi->createTask($name, $projectId, $description, $trackerId);

                    if ($res) {
                        $reply = 'Таск создан успешно. http://pm.vs58.net/issues/' . $res['issue']['id'];
                    } else {
                        $reply = 'Таск не создан. Попробуйте еще раз';
                    }
                } else {
                   $reply = 'Вы не зашли в проект. Используйте команду !curp [id-проекта].';
                }
                break;
            case RedmineApi::CHANGE_PROJECT:

                if ($redmineApi->changeProject($msgParams[1], $msgParams[2])) {
                    $reply = 'Изменен проект задачи.';
                } else {
                    $reply = 'Ошибка. Проект задачи не изменен.';
                }
                break;
            case RedmineApi::CLOSE_ISSUE:
                $issueId = isset($msgParams[1]) ? intval($msgParams[1]) : false;
                $reply = 'Ошибка. Таск закрыть не получилось. попробуйте еще раз.';

                if ($issueId && $redmineApi->closeIssue($issueId)) {
                    $reply = 'Таск закрыт';
                }

                break;
            case RedmineApi::ASSIGN_USER:
                break;
            case RedmineApi::GET_MY_TASKS:

                //$redmineApi->getMyTask();
                break;
            case RedmineApi::GET_TASK:
                $reply = $redmineApi->getIssueById($msgParams[1]);
                break;
            case RedmineApi::GET_PROJECTS:
                break;
            case RedmineApi::ON_TEST:
                $issueId = isset($msgParams[1]) ? intval($msgParams[1]) : 0;
                $statusId = 8;

                if ($redmineApi->changeIssueStatus($issueId, $statusId)) {
                    $reply = 'Статус задачи изменен.';
                } else {
                    $reply = 'Ошибка. Не получилось изменить статус задачи.';
                }

                break;
            case RedmineApi::COMMENT:
                $issueId = $msgParams[1];
                $comment = $msgParams[2];

                if ($redmineApi->changeComment($issueId, $comment)) {
                    $reply = 'Комментарий к задаче изменен';
                } else {
                    $reply = 'Ошибка. Комментарий к задаче не изменен.';
                }

                break;
            case RedmineApi::PROJECT:
                $id = $msgParams[1];
                $redmineApi->setCurrentProject($id);
                $reply = 'Текущий проект изменен.';
                break;
            case RedmineApi::GET_CURRENT_PROJECT:
                $id = $redmineApi->getCurrentProject();
                $reply = 'Текущий проект не установлен';

                if ($id) {
                    $reply = 'Текущий проект  - ' . $id;
                }

                break;
            case RedmineApi::EXIT_PROJECT:
                $redmineApi->setCurrentProject(null);
                $reply = 'Не получилось выйти из текущего проекта';
                if (!$redmineApi->getCurrentProject()) $reply = 'Вы вышли из проекта';
                break;
            default:
                $reply = 'Команда не найдена. Чтобы просмотреть все доступные команды, используйте !help';
                break;
        }

        return $reply;
    }

    /**
     * @param $msg - входящее сообщение
     * формируем ответ на сообщение
     *
     */
    public function getReply($msg)
    {
        return $this->actionCommand($msg);
    }
}